﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.Net.Sockets;

namespace MyServer.Common
{

    /*数据发送基类说明
     * 工作方式：
     * 1.启动发送工作流(SendMainTask)
     *   发送工作流执行->检测发送队列是否为空是则监听并重复此步，否则开始发送队列中最先到达的数据。
     * 2.执行时会取出发送队列中最先到达的数据并异步操作
     * 3.读取完毕后会同步执行OnSendCompelete事件
     * 4.发送数据之前会同步调用OnBeforeSend，当且仅当该方法返回值为真时继续发送，否则跳过发送当前数据
     */

    /// <summary>
    /// 表示数据发送器基类
    /// </summary>
    public abstract class DataSenderBase
    {

        #region ========私有变量========

        /// <summary>
        /// 线程锁对象
        /// </summary>
        private static object lockobj = new object();
        /// <summary>
        /// 一个标记，用来指示是否应该停止发送器
        /// </summary>
        private bool IsStop = false;

        #endregion

        #region========公有属性========

        /// <summary>
        /// 数据列表侦听主工作流
        /// </summary>
        public Task ListenMainTask { get; private set; }
        /// <summary>
        /// 数据发送主工作流
        /// </summary>
        public Task SendMainTask { get; private set; }
        /// <summary>
        /// 数据发送队列
        /// </summary>
        public Queue SendQueue { get; private set; }
        /// <summary>
        /// 获取或设置发送器等待队列的速率
        /// </summary>
        public int ListenRate { get; set; }

        /// <summary>
        /// 获取与发送器绑定的数据中心
        /// </summary>
        public DataCenterBase DataCenter { get; private set; }

        #endregion

        #region========公有委托========

        /// <summary>
        /// 发送完成事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void SendCompeleteEventHandler(object sender, ref DataAfterTransportEventArgs e);

        /// <summary>
        /// 发送之前事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void BeforeSendEventHandler(object sender, ref DataBeforeTransportEventArgs e);

        /// <summary>
        /// 发生错误时的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ErrorCatchedEventHandler(object sender, ref ErrorCatchedEventArgs e);

        #endregion

        #region========私有函数========

        /// <summary>
        /// 私有侦听函数
        /// </summary>
        protected virtual void DoListen()
        {
            lock (lockobj)
            {
                while (SendQueue.Count == 0 && IsStop == false)
                {
                    System.Threading.Thread.Sleep(ListenRate);
                }

                if (IsStop)
                    return;

                if (SendMainTask.Status != TaskStatus.Running)
                {
                    SendMainTask.Start();
                }
                this.ListenMainTask = new Task(DoListen);
            }
        }

        /// <summary>
        /// 私有发送函数
        /// </summary>
        protected virtual void DoSend()
        {
            lock (lockobj)//锁定语句块以确保线程安全
            {
                while (SendQueue.Count > 0 && IsStop == false)
                {
                    DataPackageCollection pkg =(DataPackageCollection)SendQueue.Dequeue();//取出发送队列最前面的数据包列表
                    DataBeforeTransportEventArgs e = new DataBeforeTransportEventArgs(pkg);//发送前事件委托
                    DataAfterTransportEventArgs e1 = new DataAfterTransportEventArgs(pkg);//发送完毕事件委托 
                    pkg.IsRecive = false;
                    if (pkg.PrecedenceLeft - 1 <= 0 || pkg.PrecedenceLeft > pkg.Precedence)//判定优先级
                    {
                        if (OnBeforeSend != null)
                            OnBeforeSend(this, ref e);//触发事件
                        if (!e.Canceled)//是否取消执行
                        {
                            bool IsSucceed = false;
                            try
                            {
                                IsSucceed = Send(ref pkg);
                            }
                            catch (Exception ex)
                            {
                                ErrorCatchedEventArgs e2 = new ErrorCatchedEventArgs(ex, pkg);
                                e2.Operate = ErrorOperate.RemoveCol;
                                if (ErrorCatched != null)
                                {
                                    ErrorCatched(this, ref e2);
                                }
                                switch (e2.Operate)
                                {
                                    case ErrorOperate.RemoveCol:
                                        continue;
                                    case ErrorOperate.StopSend:
                                        return;
                                    case ErrorOperate.Pass:
                                        break;
                                    case ErrorOperate.ClearQueue:
                                        SendQueue.Clear();
                                        break;
                                }
                                IsSucceed = false;
                            }
                            e1.IsSucceed = IsSucceed;
                        }
                        else
                        {
                            e1.IsSucceed = false;//设置成功标记为假
                        }
                        e1.Canceled = e.Canceled;//设置取消状态
                        pkg.PrecedenceLeft = pkg.Precedence;//重置优先级 

                        if (!e.Canceled)//如果不取消发送
                        {
                            if (pkg.OperatedPkgCount < pkg.Count || pkg.State == PackageCollectionState.ReadyForSend)//判定数据包列表是否发送完毕
                            {
                                pkg.State = PackageCollectionState.Sending;
                                SendQueue.Enqueue(pkg);//未发送完则将数据包列表加至队列末尾
                            }
                            else if (pkg.OperatedPkgCount == pkg.Count)//数据包已发送完毕
                            {
                                pkg.State = PackageCollectionState.SendCompelete;
                            }
                            else//数据包发送数据出错
                            {
                                pkg.State = PackageCollectionState.ErrorSend;
                            }
                        }

                        if (OnSendCompelete != null)
                            OnSendCompelete(this, ref e1);//触发事件

                    }
                    else//未达到执行优先级
                    {
                        pkg.PrecedenceLeft--;//设置优先级
                    }
                }

                this.SendMainTask = new Task(DoSend);
                if (ListenMainTask.Status != TaskStatus.Running)//判定监听线程状态
                    ListenMainTask.Start();//开启监听线程
            }
        }

        /// <summary>
        /// 发送一个数据包集合
        /// </summary>
        /// <param name="data">要发送的数据包集合</param>
        /// <returns>一个值，表示是否正确发送数据包</returns>
        /// <remarks>在本函数操作需同步执行（入data数据一次操作不能完成可分步操作）</remarks>
        protected virtual bool Send(ref DataPackageCollection data)
        {
            lock (lockobj)
            {
                try
                {
                    MemoryStream stream =new MemoryStream();
                    lock (stream)
                    {
                        BinaryWriter bw = new BinaryWriter(stream);
                        if (data.State == PackageCollectionState.Created)
                        {
                            bw.Write(true);
                            byte[] sendbuffer = data.ToByte();
                            bw.Write(sendbuffer.Length);
                            bw.Write(sendbuffer);
                            bw.Flush();
                            data.State = PackageCollectionState.ReadyForSend;
                            data.OperatedPkgCount = 0;
                        }
                        else
                        {
                            DataPackage pkg = data[data.OperatedPkgCount];
                            bw.Write(false);
                            byte[] sendbuffer = pkg.ToByte();
                            bw.Write(sendbuffer.Length);
                            bw.Write(sendbuffer);
                            bw.Flush();
                            data.OperatedPkgCount++;
                        }
                        SendData(data.Tag, stream.ToArray());
                        return true;
                    }
                }
                catch (Exception ex)
                {
#if DEBUG
                    throw (ex);
#else
                    return false;
#endif
                }

            }
        }

        #endregion

        #region ==========事件==========

        /// <summary>
        /// 当发送器发送完毕时执行的事件
        /// </summary>
        public event SendCompeleteEventHandler OnSendCompelete;

        /// <summary>
        /// 当发送器准备发送数据时执行的事件
        /// </summary>
        public event BeforeSendEventHandler OnBeforeSend;

        /// <summary>
        /// 发生错误时
        /// </summary>
        public event ErrorCatchedEventHandler ErrorCatched;

        #endregion

        #region========公有函数========

        /// <summary>
        /// 开始监听发送队列
        /// </summary>
        public virtual void StartListen()
        {
            IsStop = false;
            if (ListenMainTask.Status != TaskStatus.Running)
            {
                ListenMainTask = new Task(DoListen);
                ListenMainTask.Start();
            }
        }

        /// <summary>
        /// 停止数据处理器
        /// </summary>
        public virtual void Stop()
        {
            this.IsStop = true;
            while (SendMainTask.Status == TaskStatus.Running || ListenMainTask.Status == TaskStatus.Running)
            {
                System.Threading.Thread.Sleep(10);
            }
        }

        #endregion

        #region========抽象函数========

        /// <summary>
        /// 向基础连接发送数据
        /// </summary>
        /// <param name="Tag">存储基础连接信息的对象</param>
        /// <returns></returns>
        protected abstract void SendData(object Tag,byte[] Data);

        #endregion

        #region========构造函数========
        public DataSenderBase(DataCenterBase Center)
        {
            //初始化工作流
            this.SendMainTask = new Task(DoSend);
            this.ListenMainTask = new Task(DoListen);
            //初始化列表
            this.SendQueue = Queue.Synchronized(new Queue());
            //初始化设定
            this.ListenRate = 10;
            this.DataCenter = Center;
        }

        #endregion

    }
}
